package cn.turboinfo.fuyang.api.domain.common.component.product

import cn.turboinfo.fuyang.api.domain.common.handler.product.ProductDataFactory
import cn.turboinfo.fuyang.api.domain.common.service.product.ProductService
import cn.turboinfo.fuyang.api.entity.common.pojo.product.Product
import org.springframework.stereotype.Component
import java.util.function.BiConsumer

@Component
class ProductAssembleHelper(
    private val productService: ProductService,
    private val productDataFactory: ProductDataFactory,
) {

    companion object {
        const val ASSEMBLE_NONE = 0
        const val ASSEMBLE_ATTACHMENT = 1 shl 0

        const val ASSEMBLE_ALL = ASSEMBLE_ATTACHMENT
    }

    fun <T> assembleProduct(
        collection: Collection<T>,
        productIdResolver: (T) -> Long?,
        productInjector: BiConsumer<T, Product?>
    ) {
        assembleProduct(collection, productIdResolver, ASSEMBLE_NONE, productInjector)
    }

    fun <T> assembleProduct(
        collection: Collection<T>,
        productIdResolver: (T) -> Long?,
        assembleFlag: Int,
        productInjector: BiConsumer<T, Product?>
    ) {
        // 生成来源对象和产品ID的映射
        val collectionMap = collection
            .associateWith {
                productIdResolver(it)
            }
        // 产品ID去重
        val productIdSet = collectionMap.values.toSet()

        val productList = productService.findByIdCollection(productIdSet)

        // 拼装附件信息
        if (assembleFlag and ASSEMBLE_ATTACHMENT != 0) {
            productDataFactory.assembleAttachment(productList)
        }

        val productIdMap = productList
            .associateBy {
                it.id
            }

        // 最后迭代注入
        collection
            .onEach {
                productInjector.accept(it, productIdMap[collectionMap[it]])
            }
    }

}

fun <T> ProductAssembleHelper.assembleProduct(
    collection: Collection<T>,
    productIdResolver: (T) -> Long?,
    assembleFlag: Int = 0,
    productInjector: (T, Product?) -> Unit
) {
    assembleProduct(collection, productIdResolver, assembleFlag, BiConsumer(productInjector))
}